package main

import (
	"io/ioutil"
	"net/http"
	"proxy/api"
	"proxy/backend"
	mylog "proxy/log"
	"sync"
	"time"

	"github.com/coreos/capnslog"
	"github.com/gorilla/websocket"
)

var log = mylog.NewOverlog("proxy", "backend")

const (
	kMaxRtcId              = 1000000
	kProxyConnWriteTimeout = 30 * time.Second
	kProxyConnReadTimeout  = 30 * time.Second
	kProxyPingInterval     = 3 * time.Second
)

func main() {

	capnslog.MustRepoLogger("proxy").SetRepoLogLevel(capnslog.INFO)

	sw := &Switch{}

	sw.setupHttpServer()

	c, err := backend.Dial(":2018", "127.0.0.1:3018")
	if err != nil {
		log.Panicf("could not connect to proxy, error: %s", err)
	}

	//log.Info("connected to proxy")

	sw.client = c

	if err := sw.server.ListenAndServe(); err != nil {
		log.Panicf("http server error: %s", err)
	}
}

type Switch struct {
	ws        *websocket.Conn
	wsMu      sync.Mutex
	server    *http.Server
	client    *backend.Client
	mu        sync.Mutex
	id        int
	lastRtcId int
}

func (s *Switch) setupHttpServer() {
	mux := http.NewServeMux()
	mux.HandleFunc("/rtc", s.handleRtc)
	s.server = &http.Server{
		Addr:    "127.0.0.1:3018",
		Handler: mux,
	}
}

func (s *Switch) handleRtc(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.NotFound(w, r)
	}
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Panicf("could not read request body")
	}

	log.Infof("receive %s", body)

	req, err := api.ParseRequest(body)

	switch req.Op {
	case api.OpCall:
		s.handleCall(w, r, req)
	case api.OpAnswer:
		s.handleAnswer(w, r, req)
	case api.OpTerminate:
		s.handleTerminate(w, r, req)
	case api.OpCandidate:
		s.handleCandidate(w, r, req)
	case api.OpSubscribe:
		s.handleSubscribe(w, r, req)
	case api.OpUnSubscribe:
		s.handleUnSubscribe(w, r, req)
	default:
		http.NotFound(w, r)
	}
}

func (s *Switch) handleCall(w http.ResponseWriter, r *http.Request, req *api.Request) {
	rsp := &api.Response{
		Op:      api.OpResponse,
		TsxId:   req.TsxId,
		Status:  0,
		Message: "",
		Sdp: &api.SessionDescription{
			Type:        "",
			Description: "",
		},
		RtcId: req.RtcId,
	}
	s.reply(w, r, rsp)
}

func (s *Switch) reply(w http.ResponseWriter, r *http.Request, rsp *api.Response) {
	buf := rsp.Encode()

	w.WriteHeader(http.StatusOK)

	log.Infof("reply %s", buf)
	w.Write(buf)
}

func (s *Switch) handleAnswer(w http.ResponseWriter, r *http.Request, req *api.Request) {
	rsp := &api.Response{
		Op:      api.OpResponse,
		TsxId:   req.TsxId,
		Status:  0,
		Message: "",
		Sdp: &api.SessionDescription{
			Type:        "",
			Description: "",
		},
	}
	s.reply(w, r, rsp)
}

func (s *Switch) handleTerminate(w http.ResponseWriter, r *http.Request, req *api.Request) {
	rsp := &api.Response{
		Op:      api.OpResponse,
		TsxId:   req.TsxId,
		Status:  0,
		Message: "",
	}
	s.reply(w, r, rsp)
	// todo: 发送RtcDestroy
}

func (s *Switch) handleCandidate(w http.ResponseWriter, r *http.Request, req *api.Request) {
	rsp := &api.Response{
		Op:      api.OpResponse,
		TsxId:   req.TsxId,
		Status:  0,
		Message: "",
	}
	s.reply(w, r, rsp)
}

func (s *Switch) handleSubscribe(w http.ResponseWriter, r *http.Request, req *api.Request) {
	rsp := &api.Response{
		Op:      api.OpResponse,
		TsxId:   req.TsxId,
		Status:  0,
		Message: "",
	}
	s.reply(w, r, rsp)
}

func (s *Switch) handleUnSubscribe(w http.ResponseWriter, r *http.Request, req *api.Request) {
	rsp := &api.Response{
		Op:      api.OpResponse,
		TsxId:   req.TsxId,
		Status:  0,
		Message: "",
	}
	s.reply(w, r, rsp)
}

func (s *Switch) handlePublish(w http.ResponseWriter, r *http.Request, req *api.Request) {
	rsp := &api.Response{
		Op:      api.OpResponse,
		TsxId:   req.TsxId,
		Status:  0,
		Message: "",
	}
	s.reply(w, r, rsp)
}

func (s *Switch) handleUnPublish(w http.ResponseWriter, r *http.Request, req *api.Request) {
	rsp := &api.Response{
		Op:      api.OpResponse,
		TsxId:   req.TsxId,
		Status:  0,
		Message: "",
	}
	s.reply(w, r, rsp)
}

//func (s *Switch) registerToProxy() error {
//	proxyUrl := url.URL{
//		Scheme: "ws",
//		Host:   ":2019",
//		Path:   "/backend",
//	}
//
//	ws, _, err := websocket.DefaultDialer.Dial(proxyUrl.String(), nil)
//	if err != nil {
//		log.Panicf("could not dial to %s: %s", proxyUrl.String(), err)
//	}
//
//	s.ws = ws
//
//	log.Infof("connected to %s", proxyUrl.String())
//
//	reg := backend.Request {
//		Op: backend.OpRegister,
//		Url: url.URL{
//			Scheme: "http",
//			Host:   s.server.Addr,
//		}.String(),
//	}
//
//	s.wsMu.Lock()
//
//	log.Infof("sending register to proxy")
//	if err := s.ws.SetWriteDeadline(time.Now().Add(kProxyConnWriteTimeout)); err != nil {
//		s.wsMu.Unlock()
//		log.Panicf("could not set proxy conn write deadline, error: %s", err)
//	}
//	if err := s.ws.WriteJSON(reg); err != nil {
//		s.wsMu.Unlock()
//		log.Panicf("could not write to proxy conn, error: %s", err)
//	}
//
//	if err := s.ws.SetWriteDeadline(time.Now().Add(kProxyConnReadTimeout)); err != nil {
//		s.wsMu.Unlock()
//		log.Panicf("could not set proxy conn read deadline, error: %s", err)
//	}
//
//	rsp := &backend.Response {}
//
//	if err := s.ws.ReadJSON(rsp); err != nil {
//		s.wsMu.Unlock()
//		log.Panicf("could not read msg: %s", err)
//	}
//
//	if rsp.Op != backend.OpResponse {
//		s.wsMu.Unlock()
//		log.Panicf("received wrong msg: %s", rsp.Op)
//	}
//
//	if rsp.Status != 0 {
//		s.wsMu.Unlock()
//		return errors.New(fmt.Sprintf("register error: %s", rsp.Message))
//	}
//
//	s.wsMu.Unlock()
//	log.Infof("registered successful, backend id is |%d|", rsp.BackendId)
//	return nil
//}
